package com.example.kekewaimaibao.user.controller;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.AES;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.kekewaimaibao.core.constant.RestConstant;
import com.example.kekewaimaibao.core.utils.RegexUtil;
import com.example.kekewaimaibao.user.model.UserDO;
import com.example.kekewaimaibao.user.service.IUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: xuxiang
 * @date: 2022/3/6 22:49 星期日
 * @description: 用户信息控制层
 * @version: 1.0
 */
@Slf4j
@RestController
@RequestMapping(UserController.PATH)
@Api(tags = "用户信息控制层")
@CrossOrigin
public class UserController {
    public final static String PATH = RestConstant.VERSION_V1 + "/user";

    @Autowired
    IUserService userService;

    /**
     * 建议弃用全表查询
     * @return
     */
    @ApiOperation(value = "所有用户列表")
    @GetMapping("/list")
    public R list() {
        List<UserDO> list = userService.list(null);
        return R.ok(list);
    }

    /**
     * 根据用户昵称进行分页条件查询
     * @param current 当前页
     * @param limit   页面大小
     * @return R
     */
    @ApiOperation(value = "分页查询")
    @PostMapping("/page/{current}/{limit}")
    public R getUserPage(@PathVariable long current, @PathVariable long limit,
                         @RequestBody(required = false) UserDO userDO) {
        Page<UserDO> page = new Page<>(current, limit);
        QueryWrapper<UserDO> wrapper = null;
        if (ObjectUtil.isNotNull(userDO)) {
            wrapper = new QueryWrapper<>();
            if (StrUtil.isNotBlank(userDO.getNickName())) {
                wrapper.like("nick_name", userDO.getNickName());
            }
        }
        userService.page(page, wrapper);
        long total = page.getTotal();
        List<UserDO> records = page.getRecords();
        Map<String, Object> map = new HashMap<>(4);
        map.put("current", current);
        map.put("limit", limit);
        map.put("total", total);
        map.put("records", records);
        return R.ok(map);
    }

    @ApiOperation(value = "新增用户")
    @PostMapping("/save")
    public R save(@RequestBody UserDO userDO) {
        boolean flag = userService.save(userDO);
        if (flag) {
            return R.ok("后台新增成功");
        } else {
            return R.failed("后台新增失败");
        }
    }

    @ApiOperation(value = "更新用户")
    @PostMapping("/update")
    public R update(@RequestBody UserDO userDO) {
        boolean flag = userService.updateById(userDO);
        if (flag) {
            return R.ok("后台更新用户成功");
        } else {
            return R.failed("后台更新用户失败");
        }
    }

    @ApiOperation(value = "删除用户")
    @PostMapping("/remove/{id}")
    public R remove(@PathVariable Long id) {
        boolean flag = userService.removeById(id);
        if (flag) {
            return R.ok("后台删除id为" + id + "的用户成功");
        } else {
            return R.failed("后台删除用户失败");
        }
    }

    @ApiOperation(value = "批量删除用户信息")
    @PostMapping("/remove-ids/{ids}")
    public R deleteBatchIds(@PathVariable("ids")String[] ids) {
        List<String> list = Arrays.asList(ids);
        boolean flag = userService.removeByIds(list);
        if (flag) {
            return R.ok("批量删除用户信息成功");
        } else {
            return R.failed("批量删除用户信息失败");
        }
    }

    @ApiOperation(value = "通过id查找用户信息")
    @GetMapping("/get-by-id/{id}")
    public R getByUserId(@PathVariable Long id) {
        UserDO userDO = userService.getById(id);
        if (ObjectUtil.isNotNull(userDO)) {
            return R.ok(userDO);
        } else {
            return R.failed("未找到id为" + id + "的用户");
        }
    }

    /**
     * 参数列表：userName,nickName,password,email,phone
     * @param userDO 用户信息
     * @return R
     */
    @ApiOperation(value = "用户注册")
    @PostMapping("/register")
    public R register(@RequestBody UserDO userDO) {
        String userName = userDO.getUserName();
        String nickName = userDO.getNickName();
        String password = userDO.getPassword();
        String email = userDO.getEmail();
        String phone = userDO.getPhone();
        if (!RegexUtil.isUserName(userName)) {
            log.info("姓名格式有误 ---> {}", userName);
            return R.failed("姓名格式有误(限16个字符，仅支持中文) ---> " + userName);
        }
        if (!RegexUtil.isNickName(nickName)) {
            log.info("昵称格式有误 ---> {}", nickName);
            return R.failed("昵称格式有误(限16个字符，支持中英文、数字、减号或下划线) ---> " + nickName);
        }
        if (!RegexUtil.isPassword(password)) {
            log.info("密码格式有误 ---> {}", password);
            return R.failed("密码格式有误(限16个字符，支持英文、数字、减号或下划线) ---> " + password);
        }
        if (!RegexUtil.isEmail(email)) {
            log.info("邮箱格式有误 ---> {}", email);
            return R.failed("邮箱格式有误 ---> " + email);
        }
        if (!RegexUtil.isPhone(phone)) {
            log.info("手机号格式有误 ---> {}", phone);
            return R.failed("手机号格式有误 ---> " + phone);
        }

        boolean flag = userService.save(userDO);
        if (flag) {
            return R.ok("success");
        } else {
            return R.failed("注册失败");
        }
    }

    /**
     * 参数列表：phone,password
     * @param userDO 用户信息
     * @return R
     */
    @ApiOperation(value = "用户登录")
    @PostMapping("/login")
    public R login(@RequestBody UserDO userDO) {
        String phone = userDO.getPhone();
        String password = userDO.getPassword();
        if (!RegexUtil.isPhone(phone)) {
            log.info("手机号格式有误 ---> {}", phone);
            return R.failed("手机号格式有误 ---> " + phone);
        }
        if (!RegexUtil.isPassword(password)) {
            log.info("密码格式有误 ---> {}", password);
            return R.failed("密码格式有误(限16个字符，支持英文、数字、减号或下划线) ---> " + password);
        }

        UserDO user = userService.getByPhone(phone);
        if (ObjectUtil.isNull(user)) {
            return R.failed("手机号输入错误");
        }
        if (!password.equals(user.getPassword())) {
            return R.failed("密码输入错误");
        } else {
            Map<String, Object> map = JSON.parseObject(JSON.toJSONString(user), Map.class);
            R result = new R();
            result.setMsg("登录成功");
            result.setData(map);
            return result;
        }
    }

    /**
     * 参数列表：phone,email,password
     * @param userDO
     * @return R
     */
    @ApiOperation("忘记密码")
    @PostMapping("/reset")
    public R resetPassword(@RequestBody UserDO userDO) {
        String phone = userDO.getPhone();
        String email = userDO.getEmail();
        String password = userDO.getPassword();

        if (!RegexUtil.isPhone(phone)) {
            log.info("手机号格式有误 ---> {}", phone);
            return R.failed("手机号格式有误 ---> " + phone);
        }
        if (!RegexUtil.isEmail(email)) {
            log.info("邮箱格式有误 ---> {}", email);
            return R.failed("邮箱格式有误 ---> " + email);
        }
        if (!RegexUtil.isPassword(password)) {
            log.info("密码格式有误 ---> {}", password);
            return R.failed("密码格式有误(限16个字符，支持英文、数字、减号或下划线) ---> " + password);
        }

        boolean flag = userService.updateByReset(phone, email, password);
        if (flag) {
            return R.ok("密码重置成功");
        } else {
            R result = R.failed("密码重置失败");
            result.setCode(520);
            return result;
        }
    }

    /**
     * 判断手机号和密码是否相等（也就是说这个功能不能更新手机号和密码）
     * @param userDO 用户信息
     * @return R
     */
    @ApiOperation(value = "设置用户信息")
    @PostMapping("/update-user")
    public R updateUserInfo(@RequestBody UserDO userDO) {
        UpdateWrapper<UserDO> wrapper = new UpdateWrapper<>();
        wrapper.eq("phone", userDO.getPhone());
        wrapper.eq("password", userDO.getPassword());
        boolean flag = userService.update(userDO, wrapper);
        if (flag) {
            return R.ok("设置成功");
        } else {
            R result = new R();
            result.setCode(520);
            return R.failed("设置失败");
        }
    }

    /**
     * 用户修改密码，根据手机号进行验证（后端没有验证是否与原密码相等）
     * @param userDO
     * @return
     */
    @ApiOperation(value = "修改密码")
    @PostMapping("/change-password")
    public R changePassword(@RequestBody UserDO userDO) {
        if (RegexUtil.isPassword(userDO.getPassword())) {
            R result = new R();
            result.setCode(520);
            return R.failed("密码格式错误");
        }
        UpdateWrapper<UserDO> wrapper = new UpdateWrapper<>();
        wrapper.eq("phone", userDO.getPhone());
        wrapper.set("password", userDO.getPassword());
        boolean flag = userService.update(userDO, wrapper);
        if (flag) {
            return R.ok("修改密码成功");
        } else {
            R result = new R();
            result.setCode(520);
            return R.failed("修改密码失败");
        }
    }

    /**
     * 前端需要传递一个包含userId和avatar的对象过来实现更新用户头像
     * @param requestMap 包含userId和avatar的对象
     * @return R
     */
    @ApiOperation(value = "更新用户头像")
    @PostMapping("/update-avatar")
    public R updateAvatar(@RequestBody Map<String, Object> requestMap) {
        Long userId = Long.parseLong(requestMap.get("userId").toString());
        String avatar = requestMap.get("avatar").toString();
        UpdateWrapper<UserDO> wrapper = new UpdateWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.set("avatar", avatar);
        boolean flag = userService.update(wrapper);
        if (flag) {
            R result = new R();
            result.setCode(200);
            result.setMsg("修改头像成功");
            return result;
        } else {
            R result = R.failed("修改头像失败");
            result.setCode(520);
            return result;
        }
    }

    // 关于加密的事由
    /**
     * 1.后端与数据库之间的加密，这个之后可以交给MyBatis-Plus去做（准确来说是去敏），
     *  使用AES，如果乱码，加一个HEX（转16进制），但是注意字段有足够长才能存下，前后端需要做好数据校验的工作
     * 2.前后端之间的加密，这个之后通过RSA（非对称加密）+AES（对称加密）的方式去实现
     */
}
